package com.example.quart.service.impl;

import com.example.quart.pojo.vo.QuartzJobVo;
import com.example.quart.service.QuartzService;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.DateBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author LiYuhang
 * @version 0.1
 * @application
 * @Date 2020/11/1 16:37
 */
@Service
public class QuartzServiceImpl implements QuartzService {
    @Autowired
    private Scheduler scheduler;

    @PostConstruct
    public void startScheduler() {
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 增加一个job
     * @param jobClass     任务实现类
     * @param quartzJobVo
     * @param jobTime      时间表达式 (这是每隔多少秒为一次任务)
     * @param jobTimes     运行的次数 （<0:表示不限次数）
     */
    @Override
    public void addJob(Class<? extends QuartzJobBean> jobClass,QuartzJobVo quartzJobVo,int jobTime,
                       int jobTimes) throws SchedulerException {
        JobDetail jobDetail = JobBuilder
                .newJob(jobClass)
                .withIdentity(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName())// 任务名称和组构成任务key
                .build();
        // 使用simpleTrigger规则
        Trigger trigger = null;
        if (jobTimes < 0) {
            trigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName())
                    .withSchedule(
                            SimpleScheduleBuilder
                                    .repeatSecondlyForever(1)
                                    .withIntervalInSeconds(jobTime)
                    )
                    .startNow()
                    .build();
        } else {
            trigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName())
                    .withSchedule(
                            SimpleScheduleBuilder
                                    .repeatSecondlyForever(1)
                                    .withIntervalInSeconds(jobTime)
                                    .withRepeatCount(jobTimes)
                    )
                    .startNow()
                    .build();
        }
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 增加一个job
     * @param jobClass     任务实现类
     * @param quartzJobVo      任务名称
     */
    @Override
    public void addJob(Class<? extends QuartzJobBean> jobClass, QuartzJobVo quartzJobVo) throws SchedulerException {
        // 创建jobDetail实例，绑定Job实现类
        // 指明job的名称，所在组的名称，以及绑定job类
        JobDetail jobDetail = JobBuilder
                .newJob(jobClass)
                .withIdentity(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName())// 任务名称和组构成任务key
                .build();
        // 定义调度触发规则
        // 使用cornTrigger规则
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName())// 触发器key
                .startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
                .withSchedule(CronScheduleBuilder.cronSchedule(quartzJobVo.getJobTime())).startNow().build();
        // 把作业和触发器注册到任务调度中
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 修改 一个job的 时间表达式
     * @param quartzJobVo
     */
    @Override
    public void updateJob(QuartzJobVo quartzJobVo) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule(quartzJobVo.getJobTime())).build();
        // 重启触发器
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    /**
     * 删除任务一个job
     * @param quartzJobVo      任务名称
     */
    @Override
    public void deleteJob(QuartzJobVo quartzJobVo) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName());
        scheduler.deleteJob(jobKey);
    }

    /**
     * 暂停一个job
     * @param quartzJobVo
     */
    @Override
    public void pauseJob(QuartzJobVo quartzJobVo) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName());
        scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复一个job
     * @param quartzJobVo
     */
    @Override
    public void resumeJob(QuartzJobVo quartzJobVo) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName());
        scheduler.resumeJob(jobKey);
    }

    /**
     * 立即执行一个job
     * @param quartzJobVo
     */
    @Override
    public void runAJobNow(QuartzJobVo quartzJobVo) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(quartzJobVo.getJobName(), quartzJobVo.getJobGroupName());
        scheduler.triggerJob(jobKey);
    }

    /**
     * 获取所有计划中的任务列表
     * @return
     */
    @Override
    public List<Map<String, Object>> findAllJob() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        List<Map<String, Object>> jobList = new ArrayList<Map<String, Object>>();
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                Map<String, Object> map = new HashMap<>();
                map.put("jobName", jobKey.getName());
                map.put("jobGroupName", jobKey.getGroup());
                map.put("previousFireTime", trigger.getPreviousFireTime());
                map.put("nextFireTime", trigger.getNextFireTime());
                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                map.put("jobStatus", triggerState.name());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    map.put("jobTime", cronExpression);
                }
                jobList.add(map);
            }
        }
        return jobList;
    }

    /**
     * 获取所有正在运行的job
     * @return
     */
    @Override
    public List<Map<String, Object>> findRunJob() throws SchedulerException {
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        List<Map<String, Object>> jobList = new ArrayList<Map<String, Object>>(executingJobs.size());
        for (JobExecutionContext executingJob : executingJobs) {
            Map<String, Object> map = new HashMap<String, Object>();
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            map.put("jobName", jobKey.getName());
            map.put("jobGroupName", jobKey.getGroup());
            map.put("previousFireTime", trigger.getPreviousFireTime());
            map.put("nextFireTime", trigger.getNextFireTime());
            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
            map.put("jobStatus", triggerState.name());
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpression = cronTrigger.getCronExpression();
                map.put("jobTime", cronExpression);
            }
            jobList.add(map);
        }
        return jobList;
    }
}
